From e6e6f10e95906d5d01087239984c9c63f63e3bdd Mon Sep 17 00:00:00 2001 From: tee-too Date: Mon, 3 Apr 2017 20:35:23 +0200 Subject: [PATCH] Add `[target.'cfg(...)']` syntax for rustc(doc)flags in .cargo/config Allow to use the Rust `cfg(...)` syntax to configure rust(doc)flags. The flags are concatenated when a build matches several `cfg`, or several `cfg` and a $triple. Fix #3499. --- src/cargo/ops/cargo_rustc/context.rs | 40 +++++++++++++-- src/doc/config.md | 10 +++- tests/rustflags.rs | 73 ++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+), 6 deletions(-) diff --git a/src/cargo/ops/cargo_rustc/context.rs b/src/cargo/ops/cargo_rustc/context.rs index b5d01cd3e..46904749f 100644 --- a/src/cargo/ops/cargo_rustc/context.rs +++ b/src/cargo/ops/cargo_rustc/context.rs @@ -11,7 +11,7 @@ use std::sync::Arc; use core::{Package, PackageId, PackageSet, Resolve, Target, Profile}; use core::{TargetKind, Profiles, Dependency, Workspace}; use core::dependency::Kind as DepKind; -use util::{self, CargoResult, ChainError, internal, Config, profile, Cfg, human}; +use util::{self, CargoResult, ChainError, internal, Config, profile, Cfg, CfgExpr, human}; use super::TargetConfig; use super::custom_build::{BuildState, BuildScripts}; @@ -178,6 +178,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> { -> CargoResult<()> { let rustflags = env_args(self.config, &self.build_config, + &self.info(&kind), kind, "RUSTFLAGS")?; let mut process = self.config.rustc()?.process(); @@ -872,22 +873,30 @@ impl<'a, 'cfg> Context<'a, 'cfg> { } pub fn rustflags_args(&self, unit: &Unit) -> CargoResult> { - env_args(self.config, &self.build_config, unit.kind, "RUSTFLAGS") + env_args(self.config, &self.build_config, self.info(&unit.kind), unit.kind, "RUSTFLAGS") } pub fn rustdocflags_args(&self, unit: &Unit) -> CargoResult> { - env_args(self.config, &self.build_config, unit.kind, "RUSTDOCFLAGS") + env_args(self.config, &self.build_config, self.info(&unit.kind), unit.kind, "RUSTDOCFLAGS") } pub fn show_warnings(&self, pkg: &PackageId) -> bool { pkg.source_id().is_path() || self.config.extra_verbose() } + + fn info(&self, kind: &Kind) -> &TargetInfo { + match *kind { + Kind::Host => &self.host_info, + Kind::Target => &self.target_info, + } + } } // Acquire extra flags to pass to the compiler from the // RUSTFLAGS environment variable and similar config values fn env_args(config: &Config, build_config: &BuildConfig, + target_info: &TargetInfo, kind: Kind, name: &str) -> CargoResult> { // We *want* to apply RUSTFLAGS only to builds for the @@ -928,13 +937,34 @@ fn env_args(config: &Config, return Ok(args.collect()); } + let mut rustflags = Vec::new(); + let name = name.chars().flat_map(|c| c.to_lowercase()).collect::(); - // Then the target.*.rustflags value + // Then the target.*.rustflags value... let target = build_config.requested_target.as_ref().unwrap_or(&build_config.host_triple); let key = format!("target.{}.{}", target, name); if let Some(args) = config.get_list_or_split_string(&key)? { let args = args.val.into_iter(); - return Ok(args.collect()); + rustflags.extend(args); + } + // ...including target.'cfg(...)'.rustflags + if let Some(ref target_cfg) = target_info.cfg { + if let Some(table) = config.get_table("target")? { + let cfgs = table.val.iter().map(|(t, _)| (CfgExpr::from_str(t), t)) + .filter_map(|(c, n)| c.map(|c| (c, n)).ok()) + .filter(|&(ref c, _)| c.matches(target_cfg)); + for (_, n) in cfgs { + let key = format!("target.'{}'.{}", n, name); + if let Some(args) = config.get_list_or_split_string(&key)? { + let args = args.val.into_iter(); + rustflags.extend(args); + } + } + } + } + + if !rustflags.is_empty() { + return Ok(rustflags); } // Then the build.rustflags value diff --git a/src/doc/config.md b/src/doc/config.md index c67463ffb..1b3ae50c6 100644 --- a/src/doc/config.md +++ b/src/doc/config.md @@ -58,7 +58,8 @@ vcs = "none" # For the following sections, $triple refers to any valid target triple, not the # literal string "$triple", and it will apply whenever that target triple is -# being compiled to. +# being compiled to. 'cfg(...)' refers to the Rust-like `#[cfg]` syntax for +# conditional compilation. [target] # For Cargo builds which do not mention --target, this is the linker # which is passed to rustc (via `-C linker=`). By default this flag is not @@ -73,6 +74,13 @@ linker = ".." # this value overrides build.rustflags when both are present rustflags = ["..", ".."] +[target.'cfg(...)'] +# Similar for the $triple configuration, but using the `cfg` syntax. +# If several `cfg` and $triple targets are candidates, then the rustflags +# are concatenated. The `cfg` syntax only applies to rustflags, and not to +# linker. +rustflags = ["..", ".."] + # Configuration keys related to the registry [registry] index = "..." # URL of the registry index (defaults to the central repository) diff --git a/tests/rustflags.rs b/tests/rustflags.rs index a03f75290..8cdd31f1b 100644 --- a/tests/rustflags.rs +++ b/tests/rustflags.rs @@ -950,6 +950,79 @@ fn target_rustflags_precedence() { execs().with_status(101)); } +#[test] +fn cfg_rustflags_normal_source() { + let p = project("foo") + .file("Cargo.toml", r#" + [package] + name = "foo" + version = "0.0.1" + "#) + .file("src/lib.rs", "") + .file("src/bin/a.rs", "fn main() {}") + .file("examples/b.rs", "fn main() {}") + .file("tests/c.rs", "#[test] fn f() { }") + .file("benches/d.rs", r#" + #![feature(test)] + extern crate test; + #[bench] fn run1(_ben: &mut test::Bencher) { }"#) + .file(".cargo/config", " + [target.'cfg(feature=\"feat\")'] + rustflags = [\"-Z\", \"bogus\"] + "); + p.build(); + + assert_that(p.cargo("build").arg("--features").arg("\"feat\"") + .arg("--lib"), + execs().with_status(101)); + assert_that(p.cargo("build").arg("--features").arg("\"feat\"") + .arg("--bin=a"), + execs().with_status(101)); + assert_that(p.cargo("build").arg("--features").arg("\"feat\"") + .arg("--example=b"), + execs().with_status(101)); + assert_that(p.cargo("test").arg("--features").arg("\"feat\""), + execs().with_status(101)); + assert_that(p.cargo("bench").arg("--features").arg("\"feat\""), + execs().with_status(101)); +} + +// target.'cfg(...)'.rustflags takes precedence over build.rustflags +#[test] +fn cfg_rustflags_precedence() { + let p = project("foo") + .file("Cargo.toml", r#" + [package] + name = "foo" + version = "0.0.1" + "#) + .file("src/lib.rs", "") + .file(".cargo/config", " + [build] + rustflags = [\"--cfg\", \"foo\"] + + [target.'cfg(feature = \"feat\"')] + rustflags = [\"-Z\", \"bogus\"] + "); + p.build(); + + assert_that(p.cargo("build").arg("--features").arg("\"feat\"") + .arg("--lib"), + execs().with_status(101)); + assert_that(p.cargo("build").arg("--features").arg("\"feat\"") + .arg("--bin=a"), + execs().with_status(101)); + assert_that(p.cargo("build").arg("--features").arg("\"feat\"") + .arg("--example=b"), + execs().with_status(101)); + assert_that(p.cargo("test").arg("--features").arg("\"feat\""), + execs().with_status(101)); + assert_that(p.cargo("bench").arg("--features").arg("\"feat\""), + execs().with_status(101)); +} + + + #[test] fn target_rustflags_string_and_array_form1() { let p1 = project("foo") -- 2.30.2